<template>
  <div style="min-height: 80px">
    <div ref="refEditor"></div>
    <a-button
      v-if="props.canEdit"
      style="position: absolute; bottom: 0; right: 0"
      @click="checkYaml()"
      >校验</a-button
    >
  </div>
</template>
<script setup>
import { ref, watch, onMounted } from "vue";
import { EditorState } from "@codemirror/state";
import { EditorView, keymap, lineNumbers } from "@codemirror/view";
import { defaultKeymap } from "@codemirror/commands";
import { yaml } from "@codemirror/lang-yaml";
import jsYaml from "js-yaml";
import { notification } from "ant-design-vue";
import { materialLight } from "@uiw/codemirror-theme-material";
import { basicSetup } from "codemirror";

const props = defineProps({
  canEdit: { type: Boolean, default: false },
  modelValue: { type: String, default: "" },
});

const emits = defineEmits(["update:modelValue"]);

const stateValue = ref(props.modelValue);

const updateValue = () => {
  emits("update:modelValue", stateValue.value);
};

const checkYaml = () => {
  try {
    let v = jsYaml.load(stateValue.value);
    stateValue.value = jsYaml.dump(v, { indent: 2 });
  } catch (e) {
    notification.error({
      message: "错误",
      description: "文档解析失败",
    });
  }
  updateValue();
};

watch(
  () => props.modelValue,
  (newValue) => {
    stateValue.value = newValue;
    if (editorView.value != undefined) {
      editorView.value.dispatch({
        changes: {
          from: 0,
          to: editorView.value.state.doc.length,
          insert: newValue,
        },
      });
    }
  }
);

const refEditor = ref(null);
const editorState = EditorState.create({
  doc: stateValue.value,
  extensions: [
    basicSetup,
    keymap.of(defaultKeymap),
    lineNumbers(),
    yaml(),
    materialLight,
    EditorView.updateListener.of((update) => {
      if (update.docChanged) {
        stateValue.value = update.state.doc.toString();
      }
    }),
    EditorState.readOnly.of(!props.canEdit),
    EditorView.editable.of(props.canEdit),
    // 编辑器失去焦点时同步编辑内容到vue model中
    EditorView.domEventHandlers({
      blur() {
        updateValue();
      },
    }),
  ],
});

const editorView = ref();

onMounted(() => {
  editorView.value = new EditorView({
    state: editorState,
    parent: refEditor.value,
  });
});
</script>
